// EXE_SqlSlicedInserter.cpp : Defines the entry point for the application.

#include "stdafx.h"
#include "EXE_SqlSlicedInserterThread.h"

#ifndef gbr_EXE_SqlSlicedInserterThread
#define gbr_EXE_SqlSlicedInserterThread

DWORD WINAPI SqlSlicedInserterThreadProc(void *pParameter);

inline void ClearMem(PVOID* pRes, int sz)
{
	for (int i = 0; i < sz; i++)
		((char*)pRes)[i] = 0;
}

PThreadData StartElThread(wchar_t *szCommandline)
{
	UNREFERENCED_PARAMETER(szCommandline);
	PThreadData pRes = (PThreadData)malloc(sizeof TThreadData); // ::CreateThreadpoolIo() ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.en/dllproc/base/thread_pool_api.htm
	if(NULL != pRes)
	{
		ClearMem((PVOID*)pRes, sizeof TThreadData);
		pRes->hThread = ::CreateThread(NULL, 0, SqlSlicedInserterThreadProc, pRes, 0, &pRes->dwThreadId);
	}
	return pRes;
}

void StopElThread(PThreadData *ppData)
{ // 
	if ((*ppData) != NULL && (*ppData)->bCancelled == false)
	{
		(*ppData)->bCancelled = true;
		//((*ppData)->output.pCloseData)(pData->output....);
		::WaitForSingleObject((*ppData)->hThread, MAX_WAIT_LENGTH);
		::TerminateThread((*ppData)->hThread, 0);
		::CloseHandle((*ppData)->hThread);
		free((*ppData));
		(*ppData) = NULL;
	}
}

#define gbr_Test_EXE_SqlSlicedInserter
bool Test(PInputDescription pInput, POutputDescription pOutput);
#define gbr_ParseCommandLine_EXE_SqlSlicedInserter
bool ParseCommandLine(PInputDescription pInput, POutputDescription pOutput);
#define gbr_InitializeFileRead_EXE_SqlSlicedInserter
bool InitializeFileRead(PInputDescription pInput);
#define gbr_InitializeDbWrite_EXE_SqlSlicedInserter
bool InitializeDbWrite(POutputDescription pOutput);
#define gbr_LoadRows_EXE_SqlSlicedInserter
__int64 LoadRows(PInputDescription pInput, POutputDescription pOutput);
#define gbr_CloseDbWrite_EXE_SqlSlicedInserter
void CloseDbWrite(POutputDescription pOutput);
#define gbr_CloseFileRead_EXE_SqlSlicedInserter
void CloseFileRead(PInputDescription pInput);

void Report_Start(TThreadData* pImport);
void Report_End(TThreadData* pImport);

void Report(TThreadData* pImport, int i, wchar_t *sz)
{
	if (pImport && pImport->c.bActive)
	{
		if(!pImport->bCancelled && ::TryEnterCriticalSection(&(pImport->c.cs)))
		{
			::SendMessage(pImport->c.hProgress, PBM_SETPOS, i, 0);
			for (int iP = 0; iP < 10; iP++)
				::SendMessage(pImport->c.hProgressBars[iP], PBM_SETPOS, 
					(i <= iP * 1000) ? 0 : (i >= ((1 + iP) * 1000)) ? 1000 : i % 1000,
					0);
			::SetWindowText(pImport->c.hStatusText, sz);
			::LeaveCriticalSection(&(pImport->c.cs));
		}
		if (0 == i)
			Report_Start(pImport);
		else if (10000 == i)
			Report_End(pImport);
	}
}

void Report_Start(TThreadData* pImport)
{ // Start
	::EnableWindow(pImport->c.hOk, false);
	::SetWindowText(pImport->c.hCancel, L"&Cancel");
	::EnableWindow(pImport->c.hCancel, true);
}

void Report_End(TThreadData* pImport)
{ // Done
	::EnableWindow(pImport->c.hOk, true);
	::SetWindowText(pImport->c.hCancel, L"&Close");
}

bool ActiveOrNotStarted(TThreadData* pImport, bool *pbEarlierActive)
{
	bool bRes = true;
	if (pImport->bCancelled)
		bRes = false;
	else if (pImport->c.bActive)
		(*pbEarlierActive) = true;
	else 
		bRes = !(*pbEarlierActive);
	return bRes;
}

DWORD WINAPI SqlSlicedInserterThreadProc(void *pParameter)
{
	TThreadData* pImport = (PThreadData)pParameter;
	bool bHasBeenActive = false;
#define B_ACTIVE ActiveOrNotStarted(pImport, &bHasBeenActive)
	for (int i = 0; i < 10000 && B_ACTIVE; i++)
	{
		::Sleep(1);
		wchar_t sz[100];
		wsprintf(sz, L"Testing...%d", i);
		Report(pImport, i, sz);
	}//*/

	if (B_ACTIVE)
		Report(pImport, 0, L"Initializing...");
	if (B_ACTIVE && ParseCommandLine(&pImport->input, &pImport->output))
	{
		Report(pImport, 1000, L"Starting...");
		::Sleep(1500);
		if (B_ACTIVE && InitializeFileRead(&pImport->input))
		{
			Report(pImport, 2000, L"Starting...");
			::Sleep(1500);
			if (B_ACTIVE && InitializeDbWrite(&pImport->output))
			{
				if (B_ACTIVE && LoadRows(&pImport->input, &pImport->output))
				{
					Report(pImport, 8000, L"Loaded rows...");
					::Sleep(1500);
				}
				Report(pImport, 9998, L"Closing file...");
				::Sleep(1500);
				CloseDbWrite(&pImport->output);
			}
			Report(pImport, 9999, L"Closing file...");
			CloseFileRead(&pImport->input);
		}
	}
	if (B_ACTIVE)
		Report(pImport, 10000, L"Done.");
	return 0;
}
#endif //gbr_EXE_SqlSlicedInserterThread

#ifdef gbr_ParseCommandLine_EXE_SqlSlicedInserter
bool ParseCommandLine(PInputDescription pInput, POutputDescription pOutput)
{
	bool bRes = false;
#ifdef gbr_Test_EXE_SqlSlicedInserter 
	bRes = true;
	// Get data loader dll name
	lstrcpy(pInput->szDllFilename, L"DLL_FileSourceReader_Template.dll");
	// Get data loader details
	lstrcpy(pInput->slice.szFilename, L"C:\\doc\\Testdata\\sakDeleted.d"); // tgr.d sakDeleted.d
	pInput->slice.iSlice = 1; // 0..2
	pInput->slice.iSliceCount = 3;
	pInput->slice.iMaxRecordSize = 65536;
	lstrcpyA(pInput->slice.cRowDelimiters, "\x0A\x0D");

	// Get data inserter dll name
	lstrcpy(pOutput->szDllFilename, L"DLL_SqlInserter_Template.dll");
	// Get data inserter details
	lstrcpy(pOutput->insert.szConnectionString, L"Data Source=localhost;Initial Catalog=BI_DSA_Extract;Integrated Security=True");
	lstrcpy(pOutput->insert.szDestination, L"K90.K90_sak_SakDeleted"); // K90_tgr_TvangsgrunnlagType K90_sak_SakDeleted
#else // !gbr_Test_EXE_SqlSlicedInserter 
	LPWSTR szCmd = GetCommandLine();
	// Get Data loader dll name
	// Get data file
	// Get data inserter dll name
	// Get table name
#endif // gbr_Test_EXE_SqlSlicedInserter 
	return bRes;
}
#endif // gbr_ParseCommandLine_EXE_SqlSlicedInserter

#ifdef gbr_InitializeFileRead_EXE_SqlSlicedInserter
bool InitializeFileRead(PInputDescription pInput)
{
	bool bRes = false;
	// Load DLL functions
	pInput->hDll = ::LoadLibraryW(pInput->szDllFilename);
	pInput->pCreateSliceTestDescription = (TCreateSliceTestDescription)GetProcAddress(pInput->hDll, "CreateSliceTestDescription");
	pInput->pOpenSlice = (TOpenSlice)GetProcAddress(pInput->hDll, "OpenSlice");
	pInput->pGetRow = (TGetRow)GetProcAddress(pInput->hDll, "GetRow");
	pInput->pCloseSlice = (TCloseSlice)GetProcAddress(pInput->hDll, "CloseSlice");

	if (NULL != pInput->pCreateSliceTestDescription)
	{
		PSliceDescription pSliceTest = (pInput->pCreateSliceTestDescription)();
		pInput->slice = *pSliceTest; // Apply test parameters from DLL
	}
	if (NULL != pInput->pOpenSlice && NULL != pInput->pGetRow && NULL != pInput->pCloseSlice)
	{ // We have DLL, now try to open the slice.
		bRes = (pInput->pOpenSlice)(&(pInput->slice));
	}

	return bRes;
}
#endif // gbr_InitializeFileRead_EXE_SqlSlicedInserter

#ifdef gbr_InitializeDbWrite_EXE_SqlSlicedInserter
bool InitializeDbWrite(POutputDescription pOutput)
{
	UNREFERENCED_PARAMETER(pOutput);
	bool bRes = false;
	return bRes;
}

#endif // gbr_InitializeDbWrite_EXE_SqlSlicedInserter

#ifdef gbr_LoadRows_EXE_SqlSlicedInserter
__int64 LoadRows(PInputDescription pInput, POutputDescription pOutput)
{
	UNREFERENCED_PARAMETER(pInput);
	UNREFERENCED_PARAMETER(pOutput);
	__int64 iRes = 0;
	return iRes;
}
#endif // gbr_LoadRows_EXE_SqlSlicedInserter

#ifdef gbr_CloseDbWrite_EXE_SqlSlicedInserter
void CloseDbWrite(POutputDescription pOutput)
{
	UNREFERENCED_PARAMETER(pOutput);
}
#endif // gbr_CloseDbWrite_EXE_SqlSlicedInserter

#ifdef gbr_CloseFileRead_EXE_SqlSlicedInserter
void CloseFileRead(PInputDescription pInput)
{
	(pInput->pCloseSlice)(&(pInput->slice));
	FreeLibrary(pInput->hDll);
}
#endif // gbr_CloseFileRead_EXE_SqlSlicedInserter

